package com.xzg.erp.process.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.xzg.erp.process.dto.GroupProcessDefinitionDto;
import com.xzg.erp.process.dto.ProcessDefinitionDto;
import com.xzg.erp.process.service.MyProcessService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.GraphicInfo;
import org.flowable.engine.*;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.flowable.bpmn.BpmnAutoLayout;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MyProcessServiceImpl implements MyProcessService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ProcessEngine processEngine;

    @Override
    @Transactional
    public void startProcess() {
        runtimeService.startProcessInstanceByKey("oneTaskProcess11");
    }


    @Override
    public List<ProcessDefinitionDto> pageDefinitions() {
        return repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionKey().asc()  // 按Key升序排序（可选）
                .list().stream().map(this::createDto).collect(Collectors.toList());
    }

    @Override
    public List<GroupProcessDefinitionDto> groupsDefinitions() {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        if (CollUtil.isNotEmpty(list)) {
            Map<String, List<ProcessDefinition>> map = list.stream().collect(Collectors.groupingBy(ProcessDefinition::getCategory));
            return map.entrySet().stream().map(entry -> {
                GroupProcessDefinitionDto group = new GroupProcessDefinitionDto();
                group.setCategory(entry.getKey());
                group.setDto(entry.getValue().stream().map(this::createDto).collect(Collectors.toList()));
                return group;
            }).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    @Override
    public void deployProcess() {

    }

    @Override
    public String definitionImage(String processDefinitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        if (bpmnModel.getLocationMap().isEmpty()) {
            try {
                new BpmnAutoLayout(bpmnModel).execute();
            } catch (Exception e) {
                log.warn("自动布局执行失败，使用备用方案: {}", e.getMessage());
                addDefaultLayoutToAllNodes(bpmnModel);
            }
        }
        ProcessDiagramGenerator diagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
        try (InputStream imageStream = diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                processEngine.getProcessEngineConfiguration().getActivityFontName(),
                processEngine.getProcessEngineConfiguration().getLabelFontName(),
                processEngine.getProcessEngineConfiguration().getAnnotationFontName(),
                null, // 类加载器（通常使用引擎配置的）
                1.0,   // 缩放比例
                true)) {
            return inputStreamToBase64(imageStream);
        } catch (IOException e) {
            log.error("获取流程图失败，原因：IO异常，流程定义ID：{}", processDefinitionId, e);
            throw new RuntimeException(e);
        }
    }

    // 备用方案：为所有节点添加默认布局
    private void addDefaultLayoutToAllNodes(BpmnModel bpmnModel) {
        final double[] yPos = {50.0}; // 起始Y位置

        bpmnModel.getProcesses().forEach(process -> {
            process.getFlowElements().forEach(element -> {
                GraphicInfo gi = bpmnModel.getGraphicInfo(element.getId());
                if (gi == null) {
                    gi = new GraphicInfo();
                    gi.setX(100.0);
                    gi.setY(yPos[0]);
                    gi.setWidth(100.0);
                    gi.setHeight(60.0);
                }

                bpmnModel.addGraphicInfo(element.getId(), gi);
                yPos[0] += 100.0; // 下一个节点下移
            });
        });
    }

    // 将输入流转换为Base64字符串
    private String inputStreamToBase64(InputStream inputStream) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            return Base64.getEncoder().encodeToString(outputStream.toByteArray());
        }
    }


    private ProcessDefinitionDto createDto(ProcessDefinition def) {
        ProcessDefinitionDto dto = new ProcessDefinitionDto();
        dto.setKey(def.getKey());
        dto.setId(def.getId());
        dto.setName(def.getName());
        dto.setDescription(def.getDescription());
        return dto;
    }
}
